import {
  Controller,
  Delete,
  Param,
  Post,
  Put,
  Query,
  UploadedFile,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { FileInterceptor } from '@nestjs/platform-express';
import {
  ApiBearerAuth,
  ApiBody,
  ApiConsumes,
  ApiHeader,
  ApiOperation,
  ApiTags,
} from '@nestjs/swagger';
import { randomUUID } from 'crypto';

import { UploadFileDto } from '@/modules/minio/dto';
import { NestMinioClientService } from '@/modules/minio/nest-minio-client.service';
import { getFileName, getFilePrefix, responseMessage } from '@/utils';
import { Logger } from '@/utils/log4js';

@ApiTags('基于Minio的文件上传')
@ApiHeader({
  name: 'Authorization',
  required: true,
  description: 'token令牌',
})
@ApiBearerAuth()
@Controller('uploader')
export class NestMinioClientController {
  constructor(private readonly minioService: NestMinioClientService) {}

  /**
   * 文件上传至Minio的temp临时文件进行存储
   * @param file
   * @param req
   */
  @UseGuards(AuthGuard('jwt'))
  @Post('/file')
  @UseInterceptors(FileInterceptor('file'))
  @ApiOperation({ summary: '文件上传至Minio存储' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    description: '文件上传至Minio存储',
    type: UploadFileDto,
  })
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
    if (!file) {
      return responseMessage(null, '上传文件为空', 400);
    }
    // 获取文件后缀
    const prefix = getFilePrefix(file.originalname);
    // 获取文件名
    const fileName = getFileName(file.originalname);
    // 生成随机文件名
    file.originalname = `${fileName}_${randomUUID().replace(/-/g, '').slice(0, 8)}.${prefix}`;
    file.path = await this.minioService.uploadFile(file?.originalname, file.buffer);
    delete file.buffer;
    return responseMessage(file);
  }

  /**
   * 存储文件至固定路径
   * @param filePath {string} 文件路径
   */
  @UseGuards(AuthGuard('jwt'))
  @Put('/file')
  @ApiOperation({ summary: '存储文件至固定路径' })
  async getFileByName(@Query('filePath') filePath: string) {
    Logger.debug(`获取Minio中的文件：${filePath}`);
    const response = await this.minioService.moveFile(filePath);
    return responseMessage(response);
  }

  /**
   * 删除Minio中的文件
   * @param fileName {string} 文件名
   */
  @UseGuards(AuthGuard('jwt'))
  @Delete('/file/:fileName')
  @ApiOperation({ summary: '删除Minio中的文件' })
  async deleteFile(@Param('fileName') fileName: string) {
    Logger.debug(`删除Minio中的文件：${fileName}`);
    const response = await this.minioService.deleteFile(fileName);
    return responseMessage(response);
  }
}
